package state

import (
	"fmt"
	"luu/number"
	"math"
)

/**
数组下标是从1 开始的
key 为整数 <= arrLen+1 的时候，放到arr里
其他值都放到_map里，
float 和 int64 作为key是一样的
把一个值设置为null 则就是设置为空洞，相当于删除这个值
*/
type LuaTable struct {
	arr  []luaValue
	_map map[luaValue]luaValue
}

func NewLuaTable(nArr, nRec int) *LuaTable {
	t := &LuaTable{}
	if nArr > 0 {
		t.arr = make([]luaValue, nArr)
	}
	if nRec > 0 {
		t._map = make(map[luaValue]luaValue, nRec)
	}
	return t
}

func (this *LuaTable) Put(key, val luaValue) {
	if key == nil {
		panic("nil key for put(..)")
	}
	if f, ok := key.(float64); ok && math.IsNaN(f) {
		panic("nan key for put()")
	}
	key = _float2Integer(key)
	if x, ok := key.(int64); ok && x >= 1 {
		if int(x) <= len(this.arr) {
			this.arr[x-1] = val
			//shrink array
			if int(x) == len(this.arr) && val == nil {
				for i := len(this.arr) - 1; this.arr[i] == nil; i-- {
					this.arr = this.arr[:i]
				}
			}
			return
		} else if int(x) == len(this.arr)+1 {
			delete(this._map, x)
			this.arr = append(this.arr, val)
			for i := x + 1; ; i++ {
				if v, contain := this._map[i]; contain {
					delete(this._map, i)
					this.arr = append(this.arr, v)
				} else {
					break
				}
			}
			return
		}
	}
	//放到map里
	if val == nil {
		delete(this._map, key)
	} else {
		if this._map == nil {
			this._map = make(map[luaValue]luaValue, 8)
		}
		this._map[key] = val
	}
}

func (this *LuaTable) Get(key luaValue) luaValue {
	if key == nil {
		panic("nil key for get(..)")
	}
	key = _float2Integer(key)
	if x, ok := key.(int64); ok && x >= 1 && int(x) <= len(this.arr) {
		return this.arr[x-1]
	}
	return this._map[key]
}

func (this *LuaTable) Len() int {
	return len(this.arr)
}

func (this *LuaTable) Print() {
	fmt.Println(this.arr)
	fmt.Println(this._map)
}

// 如果是浮点数，且可以转换为int,那就返回int的情况，否则返回自己
func _float2Integer(key luaValue) luaValue {
	if x, ok := key.(float64); ok {
		if xint, ok := number.FloatToInteger(x); ok {
			return xint
		}
	}
	if x, ok := key.(int); ok {
		return int64(x)
	}
	return key
}
